using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using HslCommunication;
using HslCommunicationEx.HslNet;
using Catastrophe.AutoSulution.EDC;
using Catastrophe.Common.AttributeEx;

namespace HslCommunicationEx.Modubs
{
	public class MbTcpDeviceOpr : BaseNetDeviceOpr
	{
		private readonly MbTcpMaster _mbTcpMaster;

		public MbTcpDeviceOpr(MbTcpMaster mbTcpMaster)
		{
			this._mbTcpMaster = mbTcpMaster;
		}

		public override Tuple<OperateResult, ComDataAttribute> CheckReadAdr(PropertyInfo property)
		{
			MbTcpDataAttribute mbTcpDataAttribute = Attribute.GetCustomAttribute(property ?? throw new InvalidOperationException(), typeof(MbTcpDataAttribute)) as MbTcpDataAttribute;
			if (mbTcpDataAttribute == null)
			{
				return new Tuple<OperateResult, ComDataAttribute>(new OperateResult
				{
					IsSuccess = false,
					Message = "当前属性未标记ComDataAttribute"
				}, null);
			}
			return new Tuple<OperateResult, ComDataAttribute>(new OperateResult
			{
				IsSuccess = true
			}, mbTcpDataAttribute);
		}

		public OperateResult CheckWriteAdr(string propertyName, MbTcpDataAttribute comAb)
		{
			if (!comAb.OprType.HasFlag(OprTypeEnum.Write))
			{
				return new OperateResult
				{
					IsSuccess = false,
					Message = "目标属性" + propertyName + "未标记Write！"
				};
			}
			if (comAb.Ignore)
			{
				return new OperateResult
				{
					IsSuccess = false,
					Message = "目标属性" + propertyName + "标记Ignore！"
				};
			}
			return new OperateResult
			{
				IsSuccess = true
			};
		}

		public override OperateResult ReadSingle<T>(string filedName, ushort len = 0)
		{
			if (filedName == null)
			{
				throw new ArgumentNullException("filedName");
			}
			PropertyInfo propertyInfo = typeof(T).GetProperties().FirstOrDefault((PropertyInfo x) => x.Name.Equals(filedName));
			if (propertyInfo != null)
			{
				Tuple<OperateResult, ComDataAttribute> tuple = this.CheckReadAdr(propertyInfo);
				if (!tuple.Item1.IsSuccess)
				{
					return tuple.Item1;
				}
				MbTcpDataAttribute mbTcpDataAttribute = (MbTcpDataAttribute)tuple.Item2;
				ushort num = (mbTcpDataAttribute.NumInputs = this.GetByteCount(propertyInfo, mbTcpDataAttribute));
				return this.Read(mbTcpDataAttribute, len);
			}
			return new OperateResult
			{
				IsSuccess = false,
				Message = "目标属性不存在"
			};
		}

		[Obsolete]
		private ushort GetByteCountCal(MbTcpDataAttribute mbAb)
		{
			if (mbAb == null)
			{
				throw new ArgumentNullException("mbAb");
			}
			ushort num = 0;
			if (mbAb.DataType > (DataTypeEnum)0)
			{
				num = (ushort)((int)(ushort)mbAb.DataType / 10);
				if ((int)num % 2 == 0)
				{
					num = (ushort)((int)num / 2);
				}
			}
			else
			{
				num = mbAb.NumInputs;
			}
			return num;
		}

		public override ushort GetByteCount(PropertyInfo property, ComDataAttribute comData)
		{
			MbTcpDataAttribute mbTcpDataAttribute = comData as MbTcpDataAttribute;
			if (mbTcpDataAttribute == null)
			{
				throw new ArgumentNullException("mbAb");
			}
			if (property.PropertyType == typeof(Array) || property.PropertyType == typeof(string))
			{
				return mbTcpDataAttribute.NumInputs;
			}
			ushort num = base.GetByteCount(property, mbTcpDataAttribute);
			if ((int)num % 2 == 0)
			{
				num = (ushort)((int)num / 2);
			}
			return num;
		}

		public override Tuple<T, OperateResult> ReadEntityMuti<T>(T dstT)
		{
			List<PropertyInfo> list = typeof(T).GetProperties().Where(delegate(PropertyInfo x)
			{
				MbTcpDataAttribute mbTcpDataAttribute2 = Attribute.GetCustomAttribute(x, typeof(MbTcpDataAttribute)) as MbTcpDataAttribute;
				return mbTcpDataAttribute2 != null && !mbTcpDataAttribute2.Ignore && mbTcpDataAttribute2.OprType.HasFlag(OprTypeEnum.Read);
			}).ToList();
			if (list.Count == 0)
			{
				return new Tuple<T, OperateResult>(null, new OperateResult
				{
					IsSuccess = false,
					Message = "未检测到可读属性"
				});
			}
			List<MbReadQueue> list2 = new List<MbReadQueue>();
			bool flag = true;
			StringBuilder stringBuilder = new StringBuilder();
			foreach (PropertyInfo item in list)
			{
				MbTcpDataAttribute mbTcpDataAttribute = Attribute.GetCustomAttribute(item, typeof(MbTcpDataAttribute)) as MbTcpDataAttribute;
				if (mbTcpDataAttribute != null && !mbTcpDataAttribute.IgnoreMultiRead)
				{
					ushort byteCount = this.GetByteCount(item, mbTcpDataAttribute);
					if (byteCount <= 0)
					{
						DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(22, 3);
						defaultInterpolatedStringHandler.AppendLiteral("目标属性");
						defaultInterpolatedStringHandler.AppendFormatted(item.Name);
						defaultInterpolatedStringHandler.AppendLiteral("解析占字节个数失败,类型为");
						defaultInterpolatedStringHandler.AppendFormatted(item.PropertyType);
						defaultInterpolatedStringHandler.AppendLiteral("自定义长度");
						defaultInterpolatedStringHandler.AppendFormatted(mbTcpDataAttribute.NumInputs);
						throw new Exception(defaultInterpolatedStringHandler.ToStringAndClear());
					}
					list2.Add(new MbReadQueue
					{
						Property = item,
						MbAdr = mbTcpDataAttribute.MbAdr,
						NumInputsCal = byteCount,
						DataType = mbTcpDataAttribute.DataType,
						MbAdrType = mbTcpDataAttribute.MbAdrType,
						CustomNuminputs = mbTcpDataAttribute.NumInputs
					});
				}
			}
			List<MbReadQueue> list3 = list2.Where((MbReadQueue x) => x.MbAdrType == MbAdrTypeEnum.InputDiscrete).ToList();
			if (list3.Count > 0)
			{
				Tuple<ushort, ushort> tuple = this.MbAdrCal(list3);
				OperateResult<bool[]> operateResult = this._mbTcpMaster.ReadDiscreteInputsSync(tuple.Item1, tuple.Item2, 0);
				if (operateResult.IsSuccess && operateResult.Content?.Length == tuple.Item2)
				{
					this.BoolSetValue(tuple.Item1, list3, dstT, operateResult.Content);
				}
				else
				{
					flag = false;
					StringBuilder stringBuilder2 = stringBuilder;
					StringBuilder stringBuilder3 = stringBuilder2;
					StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(0, 2, stringBuilder2);
					handler.AppendFormatted(operateResult.Message);
					handler.AppendFormatted(Environment.NewLine);
					stringBuilder3.Append(ref handler);
				}
			}
			List<MbReadQueue> list4 = list2.Where((MbReadQueue x) => x.MbAdrType == MbAdrTypeEnum.OutputCoil).ToList();
			if (list4.Count > 0)
			{
				Tuple<ushort, ushort> tuple2 = this.MbAdrCal(list4);
				OperateResult<bool[]> operateResult2 = this._mbTcpMaster.ReadCoilsSync(tuple2.Item1, tuple2.Item2, 0);
				if (operateResult2.IsSuccess && operateResult2.Content?.Length == tuple2.Item2)
				{
					this.BoolSetValue(tuple2.Item1, list4, dstT, operateResult2.Content);
				}
				else
				{
					flag = false;
					StringBuilder stringBuilder2 = stringBuilder;
					StringBuilder stringBuilder4 = stringBuilder2;
					StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(0, 2, stringBuilder2);
					handler.AppendFormatted(operateResult2.Message);
					handler.AppendFormatted(Environment.NewLine);
					stringBuilder4.Append(ref handler);
				}
			}
			List<MbReadQueue> list5 = list2.Where((MbReadQueue x) => x.MbAdrType == MbAdrTypeEnum.InputRegister).ToList();
			if (list5.Count > 0)
			{
				Tuple<ushort, ushort> tuple3 = this.MbAdrCal(list5);
				OperateResult<byte[]> operateResult3 = this._mbTcpMaster.ReadInputRegisterSync(tuple3.Item1, tuple3.Item2, 0);
				flag = flag && operateResult3.IsSuccess;
				if (operateResult3.IsSuccess && operateResult3.Content?.Length == tuple3.Item2 * 2)
				{
					this.ByteSetValue(tuple3.Item1, list5, dstT, operateResult3.Content);
				}
				else
				{
					flag = false;
					StringBuilder stringBuilder2 = stringBuilder;
					StringBuilder stringBuilder5 = stringBuilder2;
					StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(0, 2, stringBuilder2);
					handler.AppendFormatted(operateResult3.Message);
					handler.AppendFormatted(Environment.NewLine);
					stringBuilder5.Append(ref handler);
				}
			}
			List<MbReadQueue> list6 = list2.Where((MbReadQueue x) => x.MbAdrType == MbAdrTypeEnum.HoldingRegister).ToList();
			if (list6.Count > 0)
			{
				Tuple<ushort, ushort> tuple4 = this.MbAdrCal(list6);
				OperateResult<byte[]> operateResult4 = this._mbTcpMaster.ReadHoldingRegisterSync(tuple4.Item1, tuple4.Item2, 0);
				if (operateResult4.IsSuccess && operateResult4.Content?.Length == tuple4.Item2 * 2)
				{
					this.ByteSetValue(tuple4.Item1, list6, dstT, operateResult4.Content);
				}
				else
				{
					flag = false;
					StringBuilder stringBuilder2 = stringBuilder;
					StringBuilder stringBuilder6 = stringBuilder2;
					StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(0, 2, stringBuilder2);
					handler.AppendFormatted(operateResult4.Message);
					handler.AppendFormatted(Environment.NewLine);
					stringBuilder6.Append(ref handler);
				}
			}
			return new Tuple<T, OperateResult>(dstT, new OperateResult
			{
				IsSuccess = flag,
				Message = stringBuilder.ToString()
			});
		}

		private Tuple<ushort, ushort> MbAdrCal(List<MbReadQueue> list)
		{
			ushort minAdr = list.Min((MbReadQueue x) => x.MbAdr);
			ushort num = 0;
			ushort num2 = 0;
			if (list.Count((MbReadQueue x) => x.CustomNuminputs > 0) > 0)
			{
				num = (ushort)list.Where((MbReadQueue x) => x.CustomNuminputs > 0).Max((MbReadQueue x) => x.MbAdr - minAdr + x.CustomNuminputs);
			}
			if (list.Count((MbReadQueue x) => x.CustomNuminputs == 0) > 0)
			{
				num2 = (ushort)list.Where((MbReadQueue x) => x.CustomNuminputs == 0).Max((MbReadQueue x) => x.MbAdr - minAdr + x.NumInputsCal);
			}
			ushort item = ((num > num2) ? num : num2);
			return new Tuple<ushort, ushort>(minAdr, item);
		}

		public override OperateResult WriteEntitySingle<T>(string filedName, dynamic value, ushort attempTimes = 0, ushort attempInterval = 30)
		{
			return WriteEntitySingle(typeof(T), filedName, value, attempTimes, attempInterval);
		}

		public override OperateResult WriteEntitySingle(Type entityType, string filedName, dynamic value, ushort attempTimes = 0, ushort attempInterval = 30)
		{
			if ((object)entityType == null)
			{
				throw new ArgumentNullException("entityType");
			}
			PropertyInfo propertyInfo = entityType.GetProperties().FirstOrDefault((PropertyInfo x) => x.Name.Equals(filedName));
			if (propertyInfo == null)
			{
				return new OperateResult
				{
					IsSuccess = false,
					Message = "属性不存在！"
				};
			}
			MbTcpDataAttribute mbTcpDataAttribute = Attribute.GetCustomAttribute(propertyInfo, typeof(MbTcpDataAttribute)) as MbTcpDataAttribute;
			if (mbTcpDataAttribute == null)
			{
				return new OperateResult
				{
					IsSuccess = false,
					Message = "未标记MbTcpDataAttribute"
				};
			}
			OperateResult operateResult = this.CheckWriteAdr(filedName, mbTcpDataAttribute);
			if (!operateResult.IsSuccess)
			{
				return operateResult;
			}
			OperateResult operateResult2 = Write(propertyInfo, mbTcpDataAttribute, value);
			if (operateResult2.IsSuccess)
			{
				CommRecord(mbTcpDataAttribute.IsRecord, filedName, value, OprTypeEnum.Read);
			}
			else if (!operateResult2.IsSuccess && attempTimes > 0)
			{
				attempTimes = (ushort)(attempTimes - 1);
				WriteEntitySingle(entityType, filedName, value, attempTimes);
			}
			return operateResult2;
		}

		public override OperateResult WriteEntitySingle<T>(Expression<Func<T, object>> exp, dynamic value, ushort attempTimes = 0, ushort attempInterval = 30)
		{
			string firtstOrDefaultName = base.GetFirtstOrDefaultName(exp);
			return WriteEntitySingle<T>(firtstOrDefaultName, value, attempTimes);
		}

		public override OperateResult WriteEntityMuti<T>(T entity, Expression<Func<T, object>> exp, ushort attempTimes = 0, ushort attempInterval = 30)
		{
			throw new NotImplementedException();
		}

		private void BoolSetValue<T>(int startAdr, List<MbReadQueue> list, T dstT, bool[] values)
		{
			foreach (MbReadQueue item in list)
			{
				if (item.NumInputsCal == 1 && item.Property.PropertyType == typeof(bool))
				{
					item.Property.SetValue(dstT, values[item.MbAdr]);
					base.CommRecord<MbTcpDataAttribute>(item.Property, values[item.MbAdr], OprTypeEnum.Read);
				}
				else if (item.NumInputsCal > 0 && item.Property.PropertyType == typeof(Array))
				{
					bool[] array = new bool[item.NumInputsCal];
					Array.Copy(values, item.MbAdr - startAdr, array, 0, item.NumInputsCal);
					item.Property.SetValue(dstT, array);
					base.CommRecord<MbTcpDataAttribute>(item.Property, array, OprTypeEnum.Read);
				}
			}
		}

		private void ByteSetValue<T>(int startAdr, List<MbReadQueue> list, T dstT, byte[] values)
		{
			foreach (MbReadQueue item in list)
			{
				byte[] array = new byte[item.NumInputsCal * 2];
				Array.Copy(values, (item.MbAdr - startAdr) * 2, array, 0, item.NumInputsCal * 2);
				if (item.Property.PropertyType == typeof(Array))
				{
					item.Property.SetValue(dstT, array);
					base.CommRecord<MbTcpDataAttribute>(item.Property, array, OprTypeEnum.Read);
				}
				else
				{
					dynamic valueDynamic = this.GetValueDynamic(item.Property.PropertyType, array, 0, 0);
					item.Property.SetValue(dstT, valueDynamic);
					CommRecord<MbTcpDataAttribute>(item.Property, valueDynamic, OprTypeEnum.Read);
				}
			}
		}

		private OperateResult Read(MbTcpDataAttribute mbDataAb, ushort len = 0)
		{
			len = ((len == 0) ? mbDataAb.NumInputs : len);
			return mbDataAb.MbAdrType switch
			{
				MbAdrTypeEnum.InputDiscrete => this._mbTcpMaster.ReadDiscreteInputsSync(mbDataAb.MbAdr, len, 0), 
				MbAdrTypeEnum.OutputCoil => this._mbTcpMaster.ReadCoilsSync(mbDataAb.MbAdr, len, 0), 
				MbAdrTypeEnum.InputRegister => this._mbTcpMaster.ReadInputRegisterSync(mbDataAb.MbAdr, len, 0), 
				MbAdrTypeEnum.HoldingRegister => this._mbTcpMaster.ReadHoldingRegisterSync(mbDataAb.MbAdr, len, 0), 
				_ => new OperateResult
				{
					IsSuccess = false,
					Message = "不支持的地址类型"
				}, 
			};
		}

		private OperateResult Write(PropertyInfo property, MbTcpDataAttribute mbDataAb, dynamic value)
		{
			switch (mbDataAb.MbAdrType)
			{
			case MbAdrTypeEnum.OutputCoil:
			{
				bool[] array = null;
				this.GetValue(property, mbDataAb, ref value);
				if (property.PropertyType == typeof(bool))
				{
					array = new bool[1] { value };
				}
				else
				{
					if (!(property.PropertyType == typeof(Array)))
					{
						return new OperateResult
						{
							IsSuccess = false,
							Message = "不支持写的数据类型"
						};
					}
					array = value;
				}
				return this._mbTcpMaster.WriteMultipleCoilsSync(mbDataAb.MbAdr, array, 0);
			}
			case MbAdrTypeEnum.HoldingRegister:
			{
				this.GetValue(property, mbDataAb, ref value);
				byte[] values = ((!(value is string) || string.IsNullOrWhiteSpace(mbDataAb.StringEncode)) ? ((byte[])EnDeCode.ConvertToByteBuf(value, base.EndianMode, mbDataAb.ForceChangeHlByte)) : ((byte[])EnDeCode.ConvertToByteBuf(value, base.EndianMode, mbDataAb.ForceChangeHlByte, strEncode: mbDataAb.StringEncode)));
				return this._mbTcpMaster.WriteMultipleRegisterSync(mbDataAb.MbAdr, values, 0);
			}
			default:
				return new OperateResult
				{
					IsSuccess = false,
					Message = "不支持写的寄存器类型"
				};
			}
		}

		public override DataTable CreateDsSchema<T>()
		{
			return base.CreateDsSchema<T, MbTcpDataAttribute>();
		}
	}
}
